	.msfirst
;__R09SAVD__________________________________________________________________________________________
;
;	MINI ROM MONITOR FOR THE N8VEM 6809 HOST PROCESSOR (WITH I/O BOARD, STAND ALONE,SERIAL)
;
;	WRITTEN BY: DAN WERNER -- 06/26/2010
;	based on the ROM by Andrew Lynch
;
;__________________________________________________________________________________________________
;
;
BROM 	EQU	1		LET DEVICE DRIVERS KNOW CODE IS IN ROM
BDSKY	EQU	1		USE DSKY TO DISPLAY SECTOR INF
;
; DATA CONSTANTS
;__________________________________________________________________________________________________
;REGISTER		IO PORT		; FUNCTION


DRIVE	EQU	0		DRIVE ID (ADDRESS)
NCYL	EQU	1		NUMBER OF CYLINDERS
NHEAD	EQU	2		NUMBER OF HEADS
NSEC	EQU	3		NUMBER OF SECTORS/TRACK
CYL	EQU	4		CURRENT CYLINDER
HEAD	EQU	5		CURRENT HEAD
SEC	EQU	6		CURRENT SECTOR


	ORG	$F800


;__________________________________________________________________________________________________
;
; 	INITIALIZE 6809
;__________________________________________________________________________________________________	
MAIN:
	LDS	#STACK			; RESET STACK POINTER
	CLRA			        ; set direct page register to 0
	TFR	A,DPR			;
	CLRA				; CLEAR ACCUMULATOR A
	JSR	VDU_INIT		; INIT VDU
	JSR	KB_INITIALIZE		; INIT KB
	LDX	#INITMESSAGE
	JSR	DISPLAY_STRING
	CLR	TERM_X
	INC	TERM_Y
	JSR	GOTO_XY
							
	
*******************************************************************************************
* BOOT CODE
*******************************************************************************************
	LDX	#BOOTMESSAGE
	JSR	DISPLAY_STRING

CONTRL:	
	JSR	KB_waitbyte		;
					;					
	CMPA	#$2B			; floppy?
	LBEQ	BOOTF			;					
	CMPA	#$33			; hdd?
	LBEQ	BOOTH			; 
	BRA	CONTRL
	

	
*___BOOT FROM FLOPPY, TRACK 80, H 0 & 1
BOOTF:
	JSR	SETUPDRIVE
	LDU	#$1000
	LDAA	#$01
	STAA	DRIVE,U
	LDAA	#$02
	STAA	NHEAD,U
	LDAA	#$09
	STAA	NSEC,U
	LDAA	#80
	STAA	NCYL,U
	LDAA	#78
	STAA	CYL,U
	CLRA
	STAA	HEAD,U
	STAA	SEC,U
	JSR	SETTRACK
	LDX	#$C700
	JMP 	DOBOOT

*___BOOT FROM HDD, TRACK 80, H 0 & 1
BOOTH:
	JSR	IDE_SOFT_RESET
	LDU	#$1000
	LDAA	#$00
	STAA	DRIVE,U
	LDAA	#$01
	STAA	NHEAD,U
	LDAA	#$FF
	STAA	NSEC,U
	LDAA	#$FF
	STAA	NCYL,U
	LDAA	#$FD
	STAA	CYL,U
	CLRA
	STAA	HEAD,U
	STAA	SEC,U
	LDX	#$C700
	JMP 	DOBOOT

	
		
	
DOBOOT:
	IFD	BDSKY
	JSR	SEGDISPLAY
	ENDIF
	LDAA	DRIVE,U
	BNE	BOOTFL
	JSR	IDE_READ_SECTOR
	JMP 	BOOTCONT	
BOOTFL:		
	PSHS	X
	JSR	READFL
	CMPA	#$03
	BHS	BOOTRETRY
	PULS	D
	ADDD	#$0200
	PSHS	D
	PULS	X
BOOTCONT:
	CPX	#$F000
	BHS	BOOTDONE
	LDAA	SEC,U
	INCA
	STAA	SEC,U
	CMPA	NSEC,U
	BNE	DOBOOT
	CLRA
	STAA	SEC,U
	LDAA	HEAD,U
	INCA
	STAA	HEAD,U
	CMPA	NHEAD,U
	BNE	DOBOOT
	CLRA
	STAA	SEC,U
	STAA	HEAD,U
	LDAA	CYL,U
	INCA
	STAA	CYL,U
	CMPA	NCYL,U
	BNE	DOBOOT

	
	
BOOTDONE:
	JMP	$C808
BOOTRETRY:	
	LDAA	CYL,U		;
	PSHS	A
	CLRA
	STAA	CYL,U
	JSR	SETTRACK
	PULS	A
	STAA	CYL,U
	JSR	SETTRACK
	PULS	X
	BRA	DOBOOT	
		
;__________________________________________________________________________________________________________	
	

DISPLAY_STRING:	
	LDAA	,X			; GET CHAR
	BEQ	DISPLAY_STRING_END
	JSR	VDU_PutChar		; OUTPUT CHARACTER
	INX
	BRA	DISPLAY_STRING
DISPLAY_STRING_END:	
	RTS	
	


;__VDU_INIT_________________________________________________________________________________________
;
; 	INITIALIZE VDU
;__________________________________________________________________________________________________			
VDU_INIT:
	PSHS 	A,Y,X			; STORE A Y X
	JSR 	VDU_CRTInit		; INIT 6545 VDU CHIP	
	LDY 	#2048    		; SET-UP DISPLAY SIZE	
	LDAA 	#31			; TOGGLE VDU FOR UPDATE
	STAA 	SY6545S			;
	LDX	#$0000
VDU_CRTSpaceLoop:			;	
	LDAA 	#18 	           	; write X to R18 and R19 (update address)
	JSR 	VDU_HL2WREG_A  		;
	LDAA 	#31	            	; TOGGLE VDU FOR UPDATE
	STAA 	SY6545S         	;
	JSR 	VDU_UpdateCheck 	; WAIT FOR VDU TO BE READY
	LDAA 	#' '	           	; CLEAR SCREEN
	STAA 	WRITR	         	; send space to dataport
	DEY				; DECREMENT DE
	INX				;
	CPY	#$0000			; IS ZERO?
	BNE 	VDU_CRTSpaceLoop	; NO, LOOP
	LDAA 	#31 	           	; TOGGLE VDU FOR UPDATE
	STAA 	SY6545S         	;
	LDX	#$0000			; SET UP START OF DISPLAY
	STX	VDU_DISPLAY_START	; STORE DISPLAY START
	LDAA 	#12			; SAVE START OF DISPLAY TO VDU
	JSR 	VDU_HL2WREG_A		;
	PULS 	A,Y,X			;
	CLRA				; LOAD 0 INTO A
	STAA	TERM_X			; SET X COORD
	STAA	TERM_Y			; SET Y COORD
    	JMP 	VDU_CursorOn		; TURN ON CURSOR
	

;__VDU_HL2WREG_A___________________________________________________________________________________
;
; 	WRITE VALUE IN HL TO REGISTER IN A
;	A: REGISTER TO UPDATE
;	HL: WORD VALUE TO WRITE
;__________________________________________________________________________________________________			
VDU_HL2WREG_A:
	PSHS 	A			; STORE A
    	JSR 	VDU_UpdateCheck 	; WAIT FOR VDU TO BE READY
    	PULS 	A			; RESTORE A
    	STAA 	SY6545S           	; address register
    	PSHS	X			;
    	PULS	B			;
     	STAB 	SY6545D          	; write H to selected register
    	INCA 		               	; increase register number
    	STAA 	SY6545S  		; address register
    	PULS	B	         	;
    	STAB	SY6545D          	; write H to selected register
    	RTS 

;__VDU_UpdateCheck_________________________________________________________________________________
;
; 	WAIT FOR VDU TO BE READY
;__________________________________________________________________________________________________			
VDU_UpdateCheck:
	LDAA	#31
	STAA	SY6545S
VDU_UpdateCheck1:	
    	LDAA 	SY6545S          	; read address/status register
    	ANDA 	#%10000000             	; if bit 7 = 1 than an update strobe has been occured
    	BEQ	VDU_UpdateCheck1	;
	RTS
VDU_Init6845:
    FCB	 $7F, $50, $60, $0C, $1E, $02, $18, $1C, $78, $09, $60, $09, $00, $00, $00, $00

;__VDU_CRTInit_____________________________________________________________________________________
;
; 	INIT VDU CHIP
;__________________________________________________________________________________________________			   	
VDU_CRTInit:
    	PSHS 	D			; STORE D
    	PSHS	X			; STORE X
    	LDAB 	#$0010	         	; B = 16
    	LDX 	#VDU_Init6845	  	; HL = pointer to the default values
    	CLRA 		               	; A = 0
VDU_CRTInitLoop:
    	STAA 	SY6545S          	; SY6545S set register
    	PSHS	A			;
    	LDAA 	,X+	          	; load the next default value in D
    	STAA 	SY6545D        		; $F3 address
    	PULS	A			;
    	INCA				;
    	DECB 		               	; reg + 1
    	CMPB	#$00			;
    	BNE 	VDU_CRTInitLoop		; LOOP UNTIL DONE
    	PULS 	X			; RESTORE X
    	PULS 	D			; RESTORE D    	    	
    	RTS 


;__VDU_CursorOn____________________________________________________________________________________
;
; 	TURN ON CURSOR
;__________________________________________________________________________________________________			   	
VDU_CursorOn:
    	PSHS 	D			; STORE AF
    	LDAB 	#$60			; SET CURSOR VALUE
    	JMP 	VDU_CursorSet		;

;__VDU_CursorOff___________________________________________________________________________________
;
; 	TURN OFF CURSOR
;__________________________________________________________________________________________________			   	   	
VDU_CursorOff:
    	PSHS 	D			; STORE D
    	LDAB 	#$20			; SET CURSOR VALUE
VDU_CursorSet:
    	BSR 	VDU_UpdateCheck    	; WAIT FOR VDU TO BE READY
    	LDAA	#10	            	; R10, cursor start and status
    	STAA 	SY6545S			; 
    	STAB 	SY6545D	        	;
    	PULS 	D			; RESTORE D
    	RTS 

;__GOTO_XY_________________________________________________________________________________________
;
; 	MOVE CURSOR TO POSITON IN TERM_X AND TERM_Y
;__________________________________________________________________________________________________			
GOTO_XY:
	PSHS	D			; STORE D
    	PSHS 	X			; STORE X

	CLR	TEMPW			;
	LDAA	TERM_X			;
	STAA	TEMPW+1			;	
	LDAA	#80			;
    	LDAB	TERM_Y			;
    	MUL				;    	
    	ADDD	TEMPW			;
    	ADDD    VDU_DISPLAY_START	;
    	STAD	VDU_DisplayPos		;
    	LDX	VDU_DisplayPos
    	LDAA 	#18			; SET UPDATE ADDRESS IN VDU
    	JSR 	VDU_HL2WREG_A		;
    	LDAA 	#31 	           	; TOGGLE VDU FOR UPDATE
    	STAA 	SY6545S         	;
    	LDAA 	#14	            	; set cursor pos
    	JSR 	VDU_HL2WREG_A		;
    	PULS 	X			; RESTORE X
   	PULS 	D			; RESTORE D
    	RTS 

;__VDU_PutChar______________________________________________________________________________________
;
; 	PLACE CHARACTER ON SCREEN
;	A: CHARACTER TO OUTPUT
;__________________________________________________________________________________________________			   	   	
VDU_PutChar:
    	BSR 	GOTO_XY	        	; 
    	STAA 	WRITR			; OUTPUT CHAR TO VDU
					;    	
    	LDAA	TERM_X			; PLACE X COORD IN A
    	INCA				; INC X COORD
    	STAA	TERM_X			; STORE IN A
    	CMPA	#80			; IS 80?
    	BNE	VDU_PutChar1		; NO, PLACE CHAR ON DISPLAY
    	CLR	TERM_X			; YES, WRAP TO NEXT LINE
    	LDAA	TERM_Y			; A= Y COORD
    	INCA				; INC Y COORD
    	STAA	TERM_Y			; STORE Y
VDU_PutChar1:    
    	BRA 	GOTO_XY	        	; 

;__KB_INITIALIZE___________________________________________________________________________________
;
; 	initialise - clear some locations and send a reset to the keyboard
;__________________________________________________________________________________________________			   	   	
KB_INITIALIZE:
	JSR 	KB_SETPORTC		; sets port c so can input and output
	JSR 	KB_RESET		; reset to the keyboard
	LDAA 	#200			; 1 second delay as keyboard sends stuff back when reset
	JSR 	KB_delay		; ignore anything back after a reset
	CLRA				; EMPTY KB QUEUE
	RTS 

;__KB_RESET________________________________________________________________________________________
;
; 	RESET THE KEYBOARD
;__________________________________________________________________________________________________			   	   	
KB_RESET:
	JSR 	KB_datahigh		;
	JSR 	KB_clockhigh		;
	LDAB 	#255			;
sf1:	DECB
	BNE 	sf1			;
	JSR 	KB_clocklow		; step 1
	LDAB 	#255			;
sf2:	DECB	
	BNE 	sf2			;
	JSR 	KB_datalow		; step 2
	JSR 	KB_clockhigh		; step 3
	JSR 	KB_waitclocklow		; step 4
	LDAB	#9			; 8 data bits + 1 parity bit low
sf3:	JSR 	KB_datahigh		; step 5
	JSR 	KB_waitclockhigh	; step 6
	JSR 	KB_waitclocklow		; step 7
	DECB
	BNE 	sf3			;
	JSR 	KB_datahigh		; step9
	JSR 	KB_waitclocklow		; step 10 could read the ack bit here if want to
	JSR 	KB_waitclockhigh	; step 11
	LDAB 	#255			;	
sf4:	DECB
	BNE 	sf4			; finish up delay
	RTS 
	
;__KB_SETPORTC_____________________________________________________________________________________
;
; 	SETUP PORT C OF 8255 FOR KEYBOARD
;__________________________________________________________________________________________________			   	   	
KB_SETPORTC:
	LDAA 	#%10000010		; a=out b=IN, c high=OUT, clow=out
	STAA 	PPICONT 		; PPI control port
	LDAA	#%00000000		; port A to zero as need this for comms to work
	STAA 	PPIA			; PPI port A
	JSR 	KB_datahigh		;
	JSR 	KB_clockhigh		;
	CLRA 				;
	RTS 
KB_datahigh:
	LDAA 	#%01111001		; see the 8255 data sheet
	BRA	KB_SETBITS		;
KB_datalow:				;
	LDAA 	#%01111000		; see the 8255 data sheet
	BRA	KB_SETBITS		;    	
KB_clockhigh:				;
	LDAA	#%01111011		; bit 5 high
	BRA	KB_SETBITS		;
KB_clocklow:				;				;
	LDAA 	#%01111010		;
KB_SETBITS:				;
	STAA 	PPICONT			;
	RTS 				;
    	
;__KB_waitbyte_____________________________________________________________________________________
;
; wait for a byte - tests a number of times if there is a keyboard input,
; overwrites all registers, returns byte in a
;__________________________________________________________________________________________________			   	   		
KB_waitbyte:	
	BSR	KB_clockhigh	; turn on keyboard
	LDX 	#500		; number of times to check 200=slow TYPE , 10=error, 25 ?error 50 ok - this delay has to be there otherwise weird keyup errors
wb1:	PSHS 	X		; store counter
	JSR 	KB_readbits	; test for a low on the clock line
	PULS 	X		; get the counter back
	CMPA	#$00		; test for a zero back from readbits
	BNE	wb2		; if not a zero then must have a byte ie a keyboard press
	DEX			; subtract 1
	BNE	wb1		; loop waiting for a response
wb2:	PSHS 	A		; store the value in a
	BSR 	KB_clocklow	; turn off keyboard
	PULS 	A		; get back byte as clocklow erased it
	RTS 

;__KB_readbits_____________________________________________________________________________________
;
; readbits reads 11 bits in from the keyboard
; first bit is a start bit then 8 bits for the byte
; then a parity bit and a stop bit
; returns after one machine cycle if not low
; uses a, b,d, e 
; returns a=0 if no data, a= scancode (or part thereof)
;__________________________________________________________________________________________________			   	   		
KB_readbits:
	LDX 	#$0008		; sample 8 times
	LDAA 	ppib
	ANDA 	#%00000010	; test the clock bit
	BNE 	KB_readbits_EXIT ; if low then start the capture
r1:	LDAB 	PPIB		; get a byte from port b
	ANDB  	#%00000010	; test the clock bit
	BEQ	R1
r2:	LDAB 	PPIB		; get a byte from port b
	ANDB  	#%00000010	; test the clock bit
	BNE	R2
	LDAB 	ppib		; sample the data line
	RORB			; move the data bit into the carry register
	RORA			; move the carry bit into bit 7 and shift right
R3:	LDAB 	PPIB		; get a byte from port b
	ANDB  	#%00000010	; test the clock bit
	BEQ	R3
	DEX			; restore for loop
	BNE 	r2		; do this 8 times
R4:	LDAB 	PPIB		; get a byte from port b
	ANDB  	#%00000010	; test the clock bit
	BNE	R4
R5:	LDAB 	PPIB		; get a byte from port b
	ANDB  	#%00000010	; test the clock bit
	BEQ	R5
R6:	LDAB 	PPIB		; get a byte from port b
	ANDB  	#%00000010	; test the clock bit
	BNE	R6
R7:	LDAB 	PPIB		; get a byte from port b
	ANDB  	#%00000010	; test the clock bit
	BEQ	R7
	RTS 
KB_readbits_EXIT:	
	CLRA
	RTS 

;__KB_waitclocklow_________________________________________________________________________________
;
; waitclocklow samples data bit 0, and waits till
; it goes low, then returns
; also times out after 0.001 seconds
; uses a, changes b
;__________________________________________________________________________________________________			   	   	
KB_waitclocklow:
	PSHS	D
	LDAB 	#255		; for timeout counter
W11L:	LDAA 	PPIB		; get a byte from port b
	ANDA  	#%00000010	; test the clock bit
	BEQ	KB_waitclocklow_EXIT 
	DECB
	BNE	W11L
KB_waitclocklow_EXIT:
	PULS	D,PC	


	
;__KB_waitclockhigh_________________________________________________________________________________
;
; waitclockhigh samples data bit 0, and waits till
; it goes high, then returns
; also times out after 0.001 seconds
; uses a, changes b
;__________________________________________________________________________________________________			   	   	
KB_waitclockHIGH:
	PSHS	D
	LDAB 	#255		; for timeout counter
W11H:	LDAA 	PPIB		; get a byte from port b
	ANDA  	#%00000010	; test the clock bit
	BNE	KB_waitclockHIGH_EXIT 
	DECB
	BNE	W11H
KB_waitclockHIGH_EXIT:
	PULS	D,PC	


;__KB_delay________________________________________________________________________________________
;
; pass A - delay is B*0.005 seconds, BCDEHL all preserved
;__________________________________________________________________________________________________			   	   	
KB_delay:	
	PSHS 	X		;
LOOP1:	LDX 	#740		; adjust this value for your clock 1481=3.68Mhz, 3219=8Mhz (test with A=1000=10 secs)
LOOP2:	DEX			; hl-1
	BNE 	LOOP2		;
	DECA			;
	BNE 	LOOP1		;
	PULS	X,PC		; restore variables & return


    	
    	
TEMPW		EQU	$2111		;
TERM_X:		EQU	$2115		; CURSOR X
TERM_Y:		EQU	$2116		; CURSOR Y
VDU_DisplayPos	EQU  	$2118		; CURRENT DISPLAY POSITION
VDU_DISPLAY_START EQU  	$211A		; CURRENT DISPLAY POSITION
READR		EQU	$F1F0		; READ VDU
WRITR		EQU	$F1F1		; WRITE VDU
SY6545S		EQU	$F1F2		; VDU STATUS/REGISTER
SY6545D		EQU	$F1F3		;
ppia		EQU	$F1F4		; PPI port A
ppib		EQU	$F1F5		; PPI port B
ppic		EQU	$F1F6		; PPI port C
ppicont		EQU	$F1F7		; PPI control port
	
	
		
	
	include CUBIXOS\CUBIDE.asm	IDE I/O DRIVERS
	include CUBIXOS\CUBFLP.asm	FLOPPY I/O DRIVERS

	IFD	BDSKY
	include CUBIXOS\CUBDSKY.asm	DSKY I/O DRIVERS
	ENDIF
	
		
BOOTMESSAGE	FCC	'BOOT FROM (F)LOPPY OR (H)DD:'
		FCB	$00
INITMESSAGE	FCC	'N8VEM 6809 ROM BOOTSTRAP LOADER'
		FCB	$00
		

; DATA
RESTAB	FCB	3,0,2,0,0,3,4,1


STACK	EQU	$2100		; STACK POINTER

; REGISTERS FOR GO
SP	EQU	$0108		; S-HIGH
	
; END REGISTERS FOR GO
CKSM	EQU	$010A		; CHECKSUM
BYTECT	EQU	$010B		; BYTE COUNT
XHI	EQU	$010C		; XREG HIGH
XLOW	EQU	$010D		; XREG LOW

* CUBIX WITH NO VDU SPACE
*	org	$FFF2
*	FCW	$E75C
*	FCW	$E758
*	FCW	$E764
*	FCW	$E760
*	FCW	$E754
*	FCW	$E768
* CUBIX WITH VDU SPACE	
	org	$FFF2
	FCW	$DE5C
	FCW	$DE58
	FCW	$DE64
	FCW	$DE60
	FCW	$DE54
	FCW	$DE68

	ORG	$FFFE		; SET RESET VECTOR TO MAIN PROGRAM
RESETV	FCW	MAIN

	END
